import 'package:flutter/material.dart';
import 'package:logger/logger.dart';

class CounterWidget extends StatefulWidget {
  final int initValue;

  const CounterWidget({Key? key, this.initValue = 0}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  final logger = Logger(printer: PrettyPrinter());
  int _counter = 0;

  @override
  void initState() {
    /**
     * 当 widget 第一次插入到 widget 树时会被调用，
     * 对于每一个State对象，Flutter 框架只会调用一次该回调，
     * 所以，通常在该回调中做一些一次性的操作，如状态初始化、订阅子树的事件通知等
     * */
    super.initState();
    _counter = widget.initValue;
    logger.i("initState");
  }

  @override
  void didChangeDependencies() {
    /**
     * 当State对象的依赖发生变化时会被调用
     * 典型的场景是当系统语言 Locale 或应用主题改变时，Flutter 框架会通知 widget 调用此回调。
     * 需要注意，组件第一次被创建后挂载的时候（包括重创建）对应的didChangeDependencies也会被调用。
     *
     * */
    super.didChangeDependencies();
    logger.i("didChangeDependencies");
  }

  @override
  Widget build(BuildContext context) {
    /**
     * 此回调读者现在应该已经相当熟悉了，它主要是用于构建 widget 子树的，会在如下场景被调用：
     *   1.在调用initState()之后。
     *   2.在调用didUpdateWidget()之后。
     *   3.在调用setState()之后。
     *   4.在调用didChangeDependencies()之后。
     *   5.在State对象从树中一个位置移除后（会调用deactivate）又重新插入到树的其它位置之后。
     * */
    logger.i("build");
    return Scaffold(
      appBar: AppBar(
        title: const Text("State生命周期"),
      ),
      body: Center(
        child: TextButton(
          child: Text(
            '             $_counter            ',
            style: const TextStyle(fontSize: 64),
          ),
          onPressed: () => setState(() => ++_counter),
        ),
      ),
    );
  }

  @override
  void didUpdateWidget(CounterWidget oldWidget) {
    /**
     * 在 widget 重新构建时，Flutter 框架会调用widget.canUpdate来检测 widget 树中同一位置的新旧节点，
     * 然后决定是否需要更新，如果widget.canUpdate返回true则会调用此回调。
     * 正如之前所述，widget.canUpdate会在新旧 widget 的 key 和 runtimeType 同时相等时会返回true，
     * 也就是说在在新旧 widget 的key和runtimeType同时相等时didUpdateWidget()就会被调用。
     *
     * */
    super.didUpdateWidget(oldWidget);
    logger.i("didUpdateWidget ");
  }

  @override
  void reassemble() {
    /**
     * 此回调是专门为了开发调试而提供的，在热重载(hot reload)时会被调用，此回调在Release模式下永远不会被调用。
     * */
    super.reassemble();
    logger.i("reassemble");
  }

  @override
  void deactivate() {
    /**
     * 当 State 对象从树中被移除时，会调用此回调。在一些场景下，Flutter 框架会将 State 对象重新插到树中，
     * 如包含此 State 对象的子树在树的一个位置移动到另一个位置时（可以通过GlobalKey 来实现）。
     * 如果移除后没有重新插入到树中则紧接着会调用dispose()方法。
     * */
    super.deactivate();
    logger.i("deactivate");
  }

  @override
  void dispose() {
    /**
     * 当 State 对象从树中被永久移除时调用；通常在此回调中释放资源。
     * */
    super.dispose();
    logger.i("dispose");
  }
}
